package _3_data_struct;

import com.google.common.collect.Lists;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Iterator;

public class FastFail {

    /**
     * 在 ArrayList 的文档注释中说明了 fast fail机制：
     * 在 ArrayList 的 iterator 被创建后 (for循环就会创建)， add 和 remove 就只能通过 iterator 的 add 和 remove 方法。
     * 如果使用 ArrayList.add 和 ArrayList.remove 方法, 就会抛出 ConcurrentModificationException
     *
     * 如果想在 for 循环中使用 add 或 remove：
     *      ⑴ 使用 iterator的 add和 remove
     *      ⑵ 使用 for i 不创建 iterator
     * {@link ArrayList.Itr#hasNext()}      {@link ArrayList.Itr#next()}
     * {@link ArrayList.Itr#checkForComodification()}
     */
    /*
    for (String item : list) { }
    是个语法糖, 在编译后, 会变成
        for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
            String item = iterator.next();
        }
    在每次循环中， 都要判断 iterator.hasNext(), 这个方法的代码只有一句：  return cursor != size;   仅仅判断了这两个值不相等。
    因此， 此例中， 在最后循环结束时
            只使用了 ArrayList.remove(Object)， 则：       cursor=2, size=1,  hasNext() 返回 true,   继续执行  iterator.next() 方法
            只使用了 ArrayList.add(Object)， 则：          cursor=2, size=3,  hasNext() 返回 true,   继续执行  iterator.next() 方法
            两个方法都用了, 那么：                         cursor=2, size=2,  hasNext() 返回 false,  不再执行  iterator.next() 方法

    而在执行 iterator.next() 方法时, 调用了 ArrayList.Itr#checkForComodification() 方法,
    判断了 expectedModCount 和 modCount 是否相等，
    在 ArrayList.add() 和 ArrayList.remove（） 方法中， 仅仅是 modCount++; 没有给 expectedModCount 赋值为 modeCount, 所以判断它不相等， 直接抛出异常
    */
    @Test
    public void testArrayListFastFail() {
        ArrayList<String> list = Lists.newArrayList("1", "2");
        int i = 1;
        for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
            System.out.println("执行第" + i + "次循环");
            String item = iterator.next();
            if ("2".equals(item)) {
                // 注意， 这里
                //      如果只有  remove(item) 会报异常
                //      如果只有  add("3") 会报异常
                //      如果两个都有, 却不会报异常
                // 原因看上面
                System.out.println("remove "+item);
                list.remove(item);
                list.add("3");
            }
            i++;
        }

        // 使用  for i
        for (int i1 = 0; i1 < list.size(); i1++) {
            String item = list.get(i1);
            if ("2".equals(item)) {
                // 注意， 这里
                //      如果只有  remove(item) 会报异常
                //      如果只有  add("3") 会报异常
                //      如果两个都有, 却不会报异常
                // 原因看上面
                System.out.println("remove "+item);
                list.remove(item);
                list.add("3");
            }
        }
    }
}
